﻿' ----------------------------------------------------------------------------------
' Microsoft Developer & Platform Evangelism
' 
' Copyright (c) Microsoft Corporation. All rights reserved.
' 
' THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 
' EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES 
' OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
' ----------------------------------------------------------------------------------
' The example companies, organizations, products, domain names,
' e-mail addresses, logos, people, places, and events depicted
' herein are fictitious.  No association with any real company,
' organization, product, domain name, email address, logo, person,
' places, or events is intended or should be inferred.
' ----------------------------------------------------------------------------------

Imports Microsoft.Samples.WindowsPhoneCloud.StorageClient.Credentials
Imports System.Xml.Linq
Imports System.Runtime.Serialization
Imports System.Net
Imports System.IO
Imports Microsoft.Samples.WindowsPhoneCloud.StorageClient.Exceptions

Public Class StorageClientExceptionParser
    Private Const DataServicesMetadataNamespace As String = "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"

    Private Shared lowerCaseDataServiceMessageXName As XName = XName.Get("message", DataServicesMetadataNamespace)
    Private Shared upperCaseDataServiceMessageXName As XName = XName.Get("Message", DataServicesMetadataNamespace)
    Private Shared dataServiceInnerErrorXName As XName = XName.Get("innererror", DataServicesMetadataNamespace)

    Private Shared lowerCaseMessageXName As XName = XName.Get("message")
    Private Shared upperCaseMessageXName As XName = XName.Get("Message")
    Private Shared innerErrorXName As XName = XName.Get("innererror")

    Private Sub New()
    End Sub

    Public Shared Function ParseDataServiceException(ByVal exception As Exception) As Exception
        If exception Is Nothing Then
            Return Nothing
        End If

        Try
            Dim baseException = exception.GetBaseException()
            Dim doc = XDocument.Parse(baseException.Message)

            Return ParseXmlExceptionDocument(doc.Root)
        Catch
            Return exception.GetBaseException()
        End Try
    End Function

    Public Shared Function ParseXmlWebException(ByVal webException As WebException) As Exception
        If webException Is Nothing Then
            Return Nothing
        End If

        Try
            Dim stream = webException.Response.GetResponseStream()
            Dim streamReader = New StreamReader(stream)
            Dim doc = XDocument.Parse(streamReader.ReadToEnd())

            Return ParseXmlExceptionDocument(doc.Root)
        Catch
            If TypeOf webException.Response Is HttpWebResponse Then
                Dim response = TryCast(webException.Response, HttpWebResponse)
                Return New HttpWebException(If(String.IsNullOrEmpty(response.StatusDescription), webException.Message, response.StatusDescription), response.StatusCode, webException)
            Else
                Return webException.GetBaseException()
            End If
        End Try
    End Function

    Public Shared Function ParseStringWebException(ByVal webException As WebException) As Exception
        If webException Is Nothing Then
            Return Nothing
        End If

        Try
            Dim serializer = New DataContractSerializer(GetType(String))
            Dim stream = webException.Response.GetResponseStream()
            Dim errorMessage = TryCast(serializer.ReadObject(stream), String)

            Return New Exception(errorMessage)
        Catch
            If TypeOf webException.Response Is HttpWebResponse Then
                Dim response = TryCast(webException.Response, HttpWebResponse)
                Return New HttpWebException(If(String.IsNullOrEmpty(response.StatusDescription), webException.Message, response.StatusDescription), response.StatusCode, webException)
            Else
                Return webException.GetBaseException()
            End If
        End Try
    End Function

    Public Shared Function ParseHttpWebException(ByVal webException As WebException) As HttpWebException
        If webException Is Nothing Then
            Return Nothing
        End If

        Dim statusCode As HttpStatusCode

        Try
            Dim response = TryCast(webException.Response, HttpWebResponse)
            statusCode = response.StatusCode

            Dim serializer = New DataContractSerializer(GetType(String))
            Dim stream = response.GetResponseStream()
            Dim errorMessage = TryCast(serializer.ReadObject(stream), String)

            Return New HttpWebException(errorMessage, statusCode, webException)
        Catch
            Return New HttpWebException(webException.Message, statusCode, webException)
        End Try
    End Function

    Private Shared Function ParseXmlExceptionDocument(ByVal errorElement As XElement) As Exception
        Select Case errorElement.Name.LocalName
            Case "error", "Error", "innererror"
                Dim innerException = If(errorElement.Element(innerErrorXName) IsNot Nothing,
                                        ParseXmlExceptionDocument(errorElement.Element(innerErrorXName)),
                                        If(errorElement.Element(dataServiceInnerErrorXName) IsNot Nothing,
                                            ParseXmlExceptionDocument(errorElement.Element(dataServiceInnerErrorXName)),
                                            Nothing))

                Dim errorMessage = String.Empty
                If errorElement.Element(lowerCaseMessageXName) IsNot Nothing Then
                    errorMessage = errorElement.Element(lowerCaseMessageXName).Value.ToString()
                ElseIf errorElement.Element(upperCaseMessageXName) IsNot Nothing Then
                    errorMessage = errorElement.Element(upperCaseMessageXName).Value.ToString()
                ElseIf errorElement.Element(lowerCaseDataServiceMessageXName) IsNot Nothing Then
                    errorMessage = errorElement.Element(lowerCaseDataServiceMessageXName).Value.ToString()
                ElseIf errorElement.Element(upperCaseDataServiceMessageXName) IsNot Nothing Then
                    errorMessage = errorElement.Element(upperCaseDataServiceMessageXName).Value.ToString()
                End If

                Return New Exception(errorMessage, innerException)

            Case Else
                Return Nothing
        End Select
    End Function
End Class
